/*
 * Open Source Physics software is free software as described near the bottom of this code file.
 *
 * For additional information and documentation on Open Source Physics please see:
 * <http://www.opensourcephysics.org/>
 */

package org.opensourcephysics.frames;
import javax.swing.*;
import org.opensourcephysics.display.*;
import org.opensourcephysics.analysis.*;
import java.awt.Color;
import org.opensourcephysics.ejs.control.GroupControl;
import java.awt.BorderLayout;
import javax.swing.border.EtchedBorder;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

/**
 * FFTRealFrame computes the FFT or real data and displays the result.
 *
 * @author W. Christian
 * @version 1.0
 */
public class FFTRealFrame extends PlotFrame {

   public static final int FREQ = 1;
   public static final int OMEGA = 2;
   protected int domainType = FREQ;
   protected int gutter = 0;
   private FourierSinCosAnalysis fft = new FourierSinCosAnalysis();
   JMenuItem connectedItem, postItem;
   GroupControl gui;
   double[] x, data;

   /**
    * A DrawingFrame that displays a FFT as its drawable.
    *
    * @param xlabel String
    * @param ylabel String
    * @param title String
    */
   public FFTRealFrame(String xlabel, String ylabel, String title) {
      super(xlabel, ylabel, title);
      setConnected(false);
      setMarkerShape(0, Dataset.POST);
      setMarkerColor(0, Color.DARK_GRAY);
      limitAutoscaleY(-1.E-5, 1.E-5);
      setXYColumnNames(0, "frequency", "power", "Power Spectrun");
      setMarkerShape(1,Dataset.POST);
      setMarkerColor(1, Color.RED);
      setXYColumnNames(1, "frequency", "re", "Real Coefficients");
      setMarkerShape(2, Dataset.POST);
      setMarkerColor(2, Color.BLUE);
      setXYColumnNames(2, "frequency", "im", "Real Coefficients");
      dataTable.setRowNumberVisible(true);
      buildUserInterface();
      showPower();
   }

   /**
    * Builds the user interface.
    */
   void buildUserInterface() {
      setSize(350,300);
      JPanel inputPanel = new JPanel();
      inputPanel.setBorder(new EtchedBorder());
      gui = new GroupControl(this); // use Easy Java Simulation components to build a user interface
      gui.addObject(inputPanel, "Panel", "name=inputPanel;layout=flow");
      gui.add("Panel", "name=radioPanel;parent=inputPanel");
      gui.add("RadioButton", "parent=radioPanel;text= sin;action=showSin()");
      gui.add("RadioButton", "parent=radioPanel;text= cos;action=showCos()");
      gui.add("RadioButton", "parent=radioPanel;text= power;action=showPower();selected=true");
      gui.add("Panel", "name=numberPanel; parent= inputPanel; layout=flow");
      gui.add("Label", "parent=numberPanel; text=added points=");
      gui.add("NumberField", "parent=numberPanel; variable=gutter; format=000; action=setGutter();size=40,16");
      getContentPane().add(inputPanel, BorderLayout.SOUTH);
   }

   public void showSin() {
      getDataset(0).setVisible(false);
      getDataset(1).setVisible(false);
      getDataset(2).setVisible(true);
      invalidateImage();
      repaint();
   }

   public void showCos() {
      getDataset(0).setVisible(false);
      getDataset(1).setVisible(true);
      getDataset(2).setVisible(false);
      invalidateImage();
      repaint();
   }

   public void showPower() {
      getDataset(0).setVisible(true);
      getDataset(1).setVisible(false);
      getDataset(2).setVisible(false);
      invalidateImage();
      repaint();
   }

   public void setGutter() {
      gutter = gui.getInt("gutter");
      doFFT();
   }

   /**
    * Adds extra points to the data before performing the Fourier analysis using the FFT.
    * @param n int
    */
   public void setGutter(int n) {
     gutter = n;
     gui.setValue("gutter",n);
     doFFT();
   }


   /**
    * Sets the x-label on the plot.
    *
    * @param xlabel String
    */
   public void setXLabel(String xlabel) {
      setXYColumnNames(0, xlabel, "power", "Power Spectrun");
      if(drawingPanel instanceof PlottingPanel) {
         ((PlottingPanel) drawingPanel).setXLabel(xlabel);
      }
   }

   /**
    * Adds Views menu items on the menu bar.
    */
   protected void addMenuItems() {
      super.addMenuItems();
      JMenuBar menuBar = getJMenuBar();
      if(menuBar==null) {
         return;
      }
      JMenu menu = getMenu(DisplayRes.getString("DrawingFrame.Views_menu"));
      if(menu==null) {
         menu = new JMenu(DisplayRes.getString("DrawingFrame.Views_menu"));
         menuBar.add(menu);
         menuBar.validate();
      } else { // add a separator if tools already exists
         menu.addSeparator();
      }
      ButtonGroup menubarGroup = new ButtonGroup();
      // post view
      postItem = new JRadioButtonMenuItem("Post View");
      menubarGroup.add(postItem);
      postItem.setSelected(true);
      ActionListener actionListener = new ActionListener() {

         public void actionPerformed(ActionEvent e) {
            convertToPostView();
         }
      };
      postItem.addActionListener(actionListener);
      menu.add(postItem);
      // connected view
      connectedItem = new JRadioButtonMenuItem("Connected View");
      menubarGroup.add(connectedItem);
      actionListener = new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            convertToConnectedView();
         }
      };
      connectedItem.addActionListener(actionListener);
      menu.add(connectedItem);
   }

   /**
    * Sets the units for the FFT output.
    * Domain types are:  MODE, FREQ, OMEGA
    *
    * @param type int
    */
   public void setDomainType(int type) {
      domainType = type;
      switch(domainType) {
         case FREQ :
            fft.useRadians(false);
            if(drawingPanel instanceof PlottingPanel) {
               ((PlottingPanel) drawingPanel).setXLabel("frequency");
            }
            break;
         case OMEGA :
            fft.useRadians(true);
            if(drawingPanel instanceof PlottingPanel) {
               ((PlottingPanel) drawingPanel).setXLabel("$\\omega$");
            }
            break;
      }
   }

   public void convertToPostView() {
      setConnected(false);
      setMarkerShape(0, Dataset.POST);
      setMarkerShape(1, Dataset.POST);
      setMarkerShape(2, Dataset.POST);
      drawingPanel.invalidateImage();
      postItem.setSelected(true);
      drawingPanel.repaint();
   }

   public void convertToConnectedView() {
      setConnected(true);
      setMarkerShape(0, Dataset.NO_MARKER);
      setMarkerShape(1, Dataset.NO_MARKER);
      setMarkerShape(2, Dataset.NO_MARKER);
      connectedItem.setSelected(true);
      drawingPanel.invalidateImage();
      drawingPanel.repaint();
   }

   /**
    * Does an FFT of the given data array.
    *
    * The data array is assumed to contain complex numbers stored as
    * successive (re,im) pairs.
    * The given array remains unchanged.
    *
    * @param data double[]
    * @param xmin double
    * @param xmax double
    */
   public void doFFT(double[] xNew, double[] dataNew, int gutter) {
      x = new double[2*(xNew.length/2)];  // only even number of points allowed
      System.arraycopy(xNew,0,x,0,x.length);
      data = new double[2*(dataNew.length/2)]; // only even number of points allowed
      System.arraycopy(dataNew,0,data,0,data.length);
      this.gutter=gutter;
      gui.setValue("gutter",gutter);
      doFFT();
   }

   void doFFT() {
      if(x==null) {
         return;
      }
      fft.doAnalysis(x, data, gutter);
      clearData();
      double[][] arrayData = fft.getData2D();
      append(0, arrayData[0], arrayData[1]); // power
      append(1, arrayData[0], arrayData[2]); // cos coef
      append(2, arrayData[0], arrayData[3]); // sin coef
      if((tableFrame!=null)&&tableFrame.isShowing()) {
         dataTable.refreshTable();
      }
      invalidateImage();
      repaint();
   }

   /**
    * Sets the axes to use a logarithmetic scale.
    */
   public void setLogScale(boolean xlog, boolean ylog) {
      if(drawingPanel instanceof PlottingPanel) {
         ((PlottingPanel) drawingPanel).setLogScale(xlog, ylog);
      }
   }
}
/*
 * Open Source Physics software is free software; you can redistribute
 * it and/or modify it under the terms of the GNU General Public License (GPL) as
 * published by the Free Software Foundation; either version 2 of the License,
 * or(at your option) any later version.
 *
 * Code that uses any portion of the code in the org.opensourcephysics package
 * or any subpackage (subdirectory) of this package must must also be be released
 * under the GNU GPL license.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
 * or view the license online at http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (c) 2007  The Open Source Physics project
 *                     http://www.opensourcephysics.org
 */
